package com.sinodata.bsm.center.bean;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.sinodata.bsm.center.cache.RelationTypeCache;
import com.sinodata.bsm.center.cache.ResRelationCache;
import com.sinodata.bsm.center.util.spring.SpringContextHolder;
import com.sinodata.bsm.common.constants.RelationConstants;
import com.sinodata.bsm.common.vo.RelationType;
import com.sinodata.bsm.common.vo.ResRelation;

/**
 * <p>
 * Description: 资源关系助手类
 * </p>
 *
 * @author liulibo
 * @version 1.0

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2012-5-22 PM 4:46:38     liulibo        1.0         To create
 * </p>
 *
 * @since 
 * @see     
 */

public class RelationHelper {

    private static ResRelationCache resRelationCache = SpringContextHolder.getBean(ResRelationCache.class);

    private static RelationTypeCache relationTypeCache = SpringContextHolder.getBean(RelationTypeCache.class);

    public RelationHelper() {

    }

    /**
     * 获取资源的父资源
     * 
     * @param resId
     * @return
     */
    public static List<ResBean> parents(Long resId) {
        Set<RelationType> relationTypes = relationTypeCache.getSelfAndSubRelationType(RelationConstants.FILIATION);
        Set<Long> relationTypesIds = new HashSet<Long>();
        for (RelationType relationType : relationTypes) {
            relationTypesIds.add(relationType.getId());
        }
        return from(resId, relationTypesIds);
    }

    /**
     * 获取资源的子资源
     * 
     * @param resId
     * @return
     */
    public static List<ResBean> children(Long resId) {
        Set<RelationType> relationTypes = relationTypeCache.getSelfAndSubRelationType(RelationConstants.FILIATION);
        Set<Long> relationTypesIds = new HashSet<Long>();
        for (RelationType relationType : relationTypes) {
            relationTypesIds.add(relationType.getId());
        }
        return to(resId, relationTypesIds);
    }

    /**
     * 递归获取子资源包含自身
     * 
     * @param resId
     * @return
     */
    public static Set<ResBean> childrenRec(Long resId) {
        Set<ResBean> resBeans = new HashSet<ResBean>();
        resBeans.add(ResBean.get(resId));
        List<ResBean> sub = children(resId);
        if (sub != null && sub.size() > 0) {
            for (ResBean resBean : sub) {
                Set<ResBean> set = childrenRec(resBean.res().getId());
                if (set != null && set.size() > 0) {
                    resBeans.addAll(set);
                }
            }
        }
        return resBeans;
    }

    /**
     * 根据一组关系类别ID获取一个资源的关系(关系进行递归，获取其子关系)一端资源
     * 例如:
     * A资源部署在B资源上，则A资源跟B资源之间是部署关系，
     * ResRelation中的froResId=A,toResId=B，relation=3
     * 该方法是根据B,3得到A。
     * 
     * @param resId
     * @param relationTypeId
     * @return
     */
    public static List<ResBean> fromRec(Long resId, Long relationTypeId) {
        //Recursive
        Set<RelationType> relationTypes = relationTypeCache.getSelfAndSubRelationType(relationTypeId);
        Set<Long> relationTypesIds = new HashSet<Long>();
        for (RelationType relationType : relationTypes) {
            relationTypesIds.add(relationType.getId());
        }
        return from(resId, relationTypesIds);
    }

    /**
     * 根据一组关系类别ID获取一个资源的关系一端资源
     * 例如:
     * A资源部署在B资源上，则A资源跟B资源之间是部署关系，
     * ResRelation中的froResId=A,toResId=B，relation=3
     * 该方法是根据B,3得到A。
     * 
     * @param resId
     * @param relationTypesIds
     * @return
     */
    public static List<ResBean> from(Long resId, Set<Long> relationTypesIds) {
        List<ResRelation> relations = resRelationCache.getResRelationsOfRes(resId);
        List<ResBean> resources = new ArrayList<ResBean>();
        if (relations != null) {
            for (ResRelation resRelation : relations) {
                if (resRelation.getEndId().longValue() == resId.longValue() && relationTypesIds.contains(resRelation.getRelationTypeId().longValue())) {
                    ResBean res = ResBean.get(resRelation.getStartId());
                    if (res != null) {
                        resources.add(res);
                    }
                }
            }
        }
        return resources;
    }

    /**
     * 根据一组关系类别ID获取一个资源的关系(关系进行递归，获取其子关系)一端资源
     * 例如:
     * A资源部署在B资源上，则A资源跟B资源之间是部署关系，
     * ResRelationValue中的froResId=A,toResId=B，relation=3
     * 该方法是根据A,3得到B。
     * 
     * 
     * @param resId
     * @param relationTypeId
     * @return
     */
    public static List<ResBean> toRec(Long resId, Long relationTypeId) {
        Set<RelationType> relationTypes = relationTypeCache.getSelfAndSubRelationType(relationTypeId);
        Set<Long> relationTypesIds = new HashSet<Long>();
        for (RelationType relationType : relationTypes) {
            relationTypesIds.add(relationType.getId());
        }
        return to(resId, relationTypesIds);
    }

    /**
     * 根据一组关系类别ID获取一个资源的关系一端资源
     * 例如:
     * A资源部署在B资源上，则A资源跟B资源之间是部署关系，
     * ResRelationValue中的froResId=A,toResId=B，relation=3
     * 该方法是根据A,3得到B。
     * 
     * @param resId
     * @param relationTypesIds
     * @return
     */
    public static List<ResBean> to(Long resId, Set<Long> relationTypesIds) {
        List<ResRelation> relations = resRelationCache.getResRelationsOfRes(resId);
        List<ResBean> resources = new ArrayList<ResBean>();
        if (relations != null) {
            for (ResRelation resRelation : relations) {
                if (resRelation.getStartId().longValue() == resId.longValue() && relationTypesIds.contains(resRelation.getRelationTypeId().longValue())) {
                    ResBean res = ResBean.get(resRelation.getEndId());
                    if (res != null) {
                        resources.add(res);
                    }
                }
            }
        }
        return resources;
    }

}
